package com.android.server.mock;

import android.content.Context;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Process;
import android.os.SystemProperties;
import android.os.mock.IMockManager;
import android.os.mock.IMockListener;
import com.android.server.mock.performer.MockPerformer;
import com.android.server.mock.performer.MockSettingsPerformer;
import android.os.mock.storage.MockStructStatVfs;
import android.text.TextUtils;
import android.util.Slog;

import com.android.server.mock.storage.MockStatFsImpl;

import java.util.Map;

// 改机服务，处理改机数据，提供改机数据
public class MockManagerService extends IMockManager.Stub {
    private static final String TAG = "MockManagerService";

    private static final String BASE_PATH = "/mnt/vendor/persist/ei/d/";

    private Context mContext;
    private HandlerThread mHandlerThread;
    private Handler mHandler;

    private DataParser dataParser;

    private static final int MSG_SET_STATIC_ENV = 1;
    private static final int MSG_SET_DYNAMIC_ENV = 2;

    class MockParam {
        public String data;
        public Map<String, String> map;
        public IMockListener mockListener;
    }

    public MockManagerService(Context context) {
        super();
        mContext = context;

        mHandlerThread = new HandlerThread(TAG);
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                Slog.d(TAG, "handleMessage msg.what=" + msg.what);
                switch (msg.what) {
                    case MSG_SET_STATIC_ENV:
                        handleStaticEnv(msg);
                        break;
                    case MSG_SET_DYNAMIC_ENV:
                        handleDynamicEnv(msg);
                        break;
                    default:
                        Slog.e(TAG, "Unknown msg " + msg.what);
                        break;
                }
            }
        };

        dataParser = new DataParser(context, BASE_PATH);
        dataParser.loadEnv(0);
    }

    private void handleStaticEnv(Message msg) {
        MockParam params = (MockParam) msg.obj;
        Map<String, String> map = params.map;
        int userId = AmUtil.getCurrentUserId();
        if (map != null && map.containsKey("userId")) {
            String userIdString = map.get("userId");
            if (!TextUtils.isEmpty(userIdString)) {
                if (TextUtils.isDigitsOnly(userIdString)) {
                    userId = Integer.parseInt(userIdString);
                } else {
                    Slog.e(TAG, "illegal userId: " + userIdString);
                    notifyListener(params.mockListener, new DataParser.ParserResult(
                            DataParser.Status.FAILED_USERID, "illegal userId: " + userIdString));
                    return;
                }
            }
        }

        // 杀死应用，清除应用数据, 防止应用感知改机变化
        // AmUtil.killBackgroundApps();
        AmUtil.clearApplicationData(mContext.getPackageManager());

        dataParser.cleanupEnvFiles(userId);

        String data = params.data;
        DataParser.ParserResult result = dataParser.handleStaticEnv(data, userId);
        notifyListener(params.mockListener, result);
        if (result.status != DataParser.Status.SUCCESS) {
            // 设置静态数据失败把所有数据清除，置为未改机状态
            dataParser.cleanupEnvFiles(userId);
            dataParser.resetEnv(userId);
        }

        // yhy modify start()
        mockSettings(userId);
        // yhy modify end()
    }

    private void handleDynamicEnv(Message msg) {
        // TODO:
    }

    private void notifyListener(IMockListener mockListener, DataParser.ParserResult result) {
        try {
            if (mockListener != null) {
                if (result.status == DataParser.Status.SUCCESS) {
                    mockListener.onSuccess();
                } else {
                    mockListener.onFailed(result.status.ordinal(), result.reason);
                }
                Slog.d(TAG, "notify result: " + result);
            }
        } catch (Exception e) {
            Slog.e(TAG, "notify Exception=" + e);
        }
    }

    @Override
    public int getPsState() {
        final long token = Binder.clearCallingIdentity();
        try {
            int ps = SystemProperties.getInt("ro.cust.ps", 0);
            return ps;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override
    public boolean isPs(int uid) {
        return getPsState() != 0 && isPsUid(uid);
    }

    @Override
    public boolean isPsUid(int uid) {
        return uid > Process.FIRST_APPLICATION_UID;
    }

    @Override
    public String getPsInfo(String key) {
        return dataParser.getInfo(key);
    }

    @Override
    public void setStaticEnv(String data, Map map, IMockListener listener) {
        Message msg = mHandler.obtainMessage();
        msg.what = MSG_SET_STATIC_ENV;
        MockParam params = new MockParam();
        params.data = data;
        params.map = (Map<String, String>) map;
        params.mockListener = listener;
        msg.obj = params;
        mHandler.sendMessage(msg);
    }

    @Override
    public void setDynamicEnv(String data, Map map, IMockListener listener) {
        Message msg = mHandler.obtainMessage();
        msg.what = MSG_SET_DYNAMIC_ENV;
        MockParam params = new MockParam();
        params.data = data;
        params.map = (Map<String, String>) map;
        params.mockListener = listener;
        msg.obj = params;
        mHandler.sendMessage(msg);
    }

    // @Override
    // public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() {
    //     return MockAccessibilityImpl.getInstance().getInstalledAccessibilityServiceList();
    // }

    // @Override
    // public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList() {
    //     return MockAccessibilityImpl.getInstance().getEnabledAccessibilityServiceList();
    // }

    // @Override
    // public MockMemoryInfo getMockMemoryInfo() {
    //     return MockMemoryImpl.getInstance().getMockMemoryInfo();
    // }

    private void mockSettings(int userId) {
        MockSettingsPerformer performer = MockPerformer.getInstance(MockSettingsPerformer.class);
        if (performer.needMock(userId)) {
            performer.initMock();
            performer.startMock(mContext);
        }
    }

    public Map<String, MockStructStatVfs> getMockStructStatVfsMap() {
        return MockStatFsImpl.getInstance().getMockStructStatVfsMap();
    }
}
